package org.jvm.instruction.references;

import org.jvm.instruction.base.Index16Instruction;
import org.jvm.rtda.Object;
import org.jvm.rtda.*;
import org.jvm.rtda.heap.*;
import org.jvm.rtda.heap.classmember.Field;
import org.jvm.rtda.heap.symref.FieldRef;
import org.jvm.rtda.thread.*;

/**
 * 从实例的实例变量获取值，压操作数栈
 *
 * @author 海燕
 * @date 2023/2/6
 */
public class GET_FIELD extends Index16Instruction {


    /**
     * 指令操作数含义为类常量池索引
     *
     * @param frame
     */
    @Override
    public void execute(Frame frame) {
        //从代码执行类常量池获取一个字段符号引用
        Klass thisClass = frame.getMethod().getKlass();
        ConstantPool constantPool = thisClass.getConstantPool();
        FieldRef fieldRef = (FieldRef) constantPool.getConstant(this.index);
        Field field = fieldRef.resolvedField(frame.getThread());
        if (field.isStatic()) {
            throw new RuntimeException("字段为静态");
        }
        String descriptor = field.getDescriptor();
        int slotId = field.getSlotId();
        OperandStack operandStack = frame.getOperandStack();
        //从操作数栈中获取被取值的实例
        Object object = operandStack.popRef();
        Slots slots = object.getFields();
        switch (descriptor.charAt(0)) {
            case 'Z':
            case 'B':
            case 'C':
            case 'S':
            case 'I':
                operandStack.pushInt(slots.getInt(slotId));
                break;
            case 'F':
                operandStack.pushFloat(slots.getFloat(slotId));
                break;
            case 'J':
                operandStack.pushLong(slots.getLong(slotId));
                break;
            case 'D':
                operandStack.pushDouble(slots.getDouble(slotId));
                break;
            case 'L':
            case '[':
                operandStack.pushRef(slots.getRef(slotId));
                break;
            default:
                throw new RuntimeException("unknow type");
        }

    }
}
